package com.behome.socket_proxy.netty_D.server;

import com.behome.socket_proxy.netty_D.Constants;
import com.behome.socket_proxy.netty_D.client.NettyClient;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class StandardDNettyServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * 管理一个全局map，保存连接进服务端的通道数量
     */
    private static ConcurrentHashMap<Channel, NettyClient> MAP = new ConcurrentHashMap<>();
    private static ConcurrentHashMap<Channel, NettyClient> MAP2 = new ConcurrentHashMap<>();

    /**
     * 有客户端连接服务器会触发此函数
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = insocket.getAddress().getHostAddress();
        //获取连接通道唯一标识
        ChannelId channelId = ctx.channel().id();
        log.info("客户端【" + channelId + "】连接指令服务器[IP:" + clientIp + "--->PORT:" + insocket.getPort() + "]");
    }

    /**
     * 有客户端终止连接服务器会触发此函数
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = insocket.getAddress().getHostAddress();
        ChannelId channelId = ctx.channel().id();
        removeChannel(ctx.channel());
        log.info("客户端【" + channelId + "】退出指令服务器[IP:" + clientIp + "--->PORT:" + insocket.getPort() + "]");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        NettyClient tcpClient = MAP.get(ctx.channel());
        if (tcpClient != null && tcpClient.getChannel() != null && tcpClient.getChannel().isActive()) {
            tcpClient.getChannel().writeAndFlush(msg);
        } else {
            tcpClient = new NettyClient(ctx, Constants.proxy1, Constants.port);
            if (tcpClient.getChannel() != null) {
                StandardDNettyServerHandler.getMap().put(ctx.channel(), tcpClient);
                tcpClient.getChannel().writeAndFlush(msg);
            }
        }

        NettyClient tcpClient2 = MAP2.get(ctx.channel());
        if (tcpClient2 != null && tcpClient2.getChannel() != null && tcpClient2.getChannel().isActive()) {
            tcpClient2.getChannel().writeAndFlush(msg);
        } else {
            tcpClient2 = new NettyClient(ctx, Constants.proxy2, Constants.port);
            if (tcpClient2.getChannel() != null) {
                StandardDNettyServerHandler.getMap2().put(ctx.channel(), tcpClient2);
                tcpClient2.getChannel().writeAndFlush(msg);
            }
        }
    }


    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        String socketString = ctx.channel().remoteAddress().toString();
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                log.debug("Client: " + socketString + " READER_IDLE 读超时");
            } else if (event.state() == IdleState.WRITER_IDLE) {
                log.debug("Client: " + socketString + " WRITER_IDLE 写超时");
            } else if (event.state() == IdleState.ALL_IDLE) {
                log.debug("Client: " + socketString + " ALL_IDLE 总超时");
            }
        }
    }

    /**
     * 发生异常会触发此函数
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.warn(ctx.channel().id() + " 发生了错误,此连接被关闭" + "此时连通数量: " + MAP.size());
        removeChannel(ctx.channel());
        cause.printStackTrace();
    }

    public static ConcurrentHashMap<Channel, NettyClient> getMap() {
        return MAP;
    }

    public static ConcurrentHashMap<Channel, NettyClient> getMap2() {
        return MAP2;
    }

    public static void removeChannel(Channel channel) {
        channel.close();
        NettyClient nettyClient = MAP.get(channel);
        NettyClient nettyClient2 = MAP2.get(channel);
        if (nettyClient != null && nettyClient.getChannel() != null) nettyClient.getChannel().close();
        if (nettyClient2 != null && nettyClient2.getChannel() != null) nettyClient2.getChannel().close();
        MAP.remove(channel);
        MAP2.remove(channel);
    }

}
